/*
 *  DefaultSessionMonitorManager.java
 * 
 *  Created on May 19, 2008, 11:31:22 PM
 */
package pl.edu.agh.ssm.monitor;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import pl.edu.agh.ssm.monitor.data.DefaultSessionDataObserver;
import pl.edu.agh.ssm.monitor.data.Session;
import pl.edu.agh.ssm.monitor.data.SessionConnection;
import pl.edu.agh.ssm.monitor.data.SessionData;
import pl.edu.agh.ssm.monitor.data.SessionDataContainer;
import pl.edu.agh.ssm.monitor.data.SessionDataObserver;
import pl.edu.agh.ssm.monitor.data.SessionMediaType;
import pl.edu.agh.ssm.monitor.data.SessionNode;
import pl.edu.agh.ssm.monitor.data.SessionNodeType;
import pl.edu.agh.ssm.monitor.gui.GUIItemDisplayer;
import pl.edu.agh.ssm.monitor.listeners.ListenerConfig;
import pl.edu.agh.ssm.monitor.listeners.PacketListener;
import pl.edu.agh.ssm.monitor.listeners.RTPSessionListener;
import pl.edu.agh.ssm.monitor.listeners.RTSPSessionListener;
import pl.edu.agh.ssm.monitor.listeners.SDPProtocolListener;
import pl.edu.agh.ssm.monitor.net.PacketFilter;
import pl.edu.agh.ssm.monitor.net.PacketReceiver;
import pl.edu.agh.ssm.monitor.plotter.ConnectionPlotter;
import pl.edu.agh.ssm.monitor.plotter.DataPlotter;
import pl.edu.agh.ssm.monitor.plotter.NodePlotter;
//import pl.edu.agh.ssm.monitor.plotter.SessionDescriptionPlotter;
import pl.edu.agh.ssm.monitor.plotter.SessionPlotter;
//import pl.edu.agh.ssm.monitor.visualization.CommandLineItemDisplayer;
import pl.edu.agh.ssm.monitor.visualization.GraphEdgeDisplayer;
import pl.edu.agh.ssm.monitor.visualization.GraphNodeDisplayer;

/**
 *
 * @author aneezka
 */
@SuppressWarnings("unchecked")
public class DefaultSessionMonitorManager implements SessionMonitorManager {

    public DefaultSessionMonitorManager() {
        displayer = new GUIItemDisplayer(SessionMonitorApp.getApplication().getView());
    }

    public NetworkInterface[] getNetworkInterfaces() {
        return JpcapCaptor.getDeviceList();
    }

    public String[] getAvailableListeners() {
        return availableListeners;
    }

    public PacketListener addListener(PacketReceiver receiver, ListenerConfig config) {
        PacketListener listener = null;
        PacketFilter filter = new PacketFilter();
        filter.setAddress(config.getIpAddress());
        filter.setPortRange(config.getLowPort(), config.getHighPort());
        if (RTP_LISTENER.equals(config.getType())) {
            listener = new RTPSessionListener(receiver);
        } else if (SDP_LISTENER.equals(config.getType())) {
            listener = new SDPProtocolListener(receiver);
        } else if (RTSP_LISTENER.equals(config.getType())) {
            listener = new RTSPSessionListener(receiver);
        } else {
            throw new IllegalArgumentException("Unknown listener type: " + config.getType());
        }
        receiver.addPacketListener(listener, filter); //general listeners, not for specified session
        return listener;
    }

    public synchronized <T extends SessionData> SessionDataContainer<T> createContainer(Class<T> aClass) {
        if (containers.containsKey(aClass)) {
            return containers.get(aClass);
        } else {
            SessionDataContainer<T> container = new SessionDataContainer<T>();
            List<DataPlotter<T>> plotters = createPlotters(aClass);
            SessionDataObserver<T> observer = new DefaultSessionDataObserver<T>();
            for (DataPlotter<T> p : plotters) {
                observer.addPlotter(p);
            }
            container.addObserver(observer);
            containers.put(aClass, container);
            return container;
        }
    }

    public List<DataPlotter<? extends SessionData>> getCreatedPlotters() {
        return addedPlotters;
    }

    private <T extends SessionData> List<DataPlotter<T>> createPlotters(Class<T> aClass) {
        List<DataPlotter<T>> result = new LinkedList<DataPlotter<T>>();
        if (aClass.equals(Session.class)) {
            DataPlotter<T> p1 = (DataPlotter<T>) new SessionPlotter();
            result.add(p1);
            addedPlotters.add(p1);
        } else if (aClass.equals(SessionNode.class)) {
        	DataPlotter<T> p1 = (DataPlotter<T>) new NodePlotter();
        	result.add(p1);
        	addedPlotters.add(p1);
        } else if(aClass.equals(SessionConnection.class)) {
        	DataPlotter<T> p1 = (DataPlotter<T>) new ConnectionPlotter();
        	result.add(p1);
        	addedPlotters.add(p1);        	
        }
        return result;
    }

	@Override
	public GraphEdgeDisplayer getEdgeDisplayer(SessionMediaType type) {
		//return new CommandLineItemDisplayer();
           return displayer;
	}

	@Override
	public GraphNodeDisplayer getNodeDisplayer(SessionNodeType type) {
	//	return new CommandLineItemDisplayer();
            return displayer;
	}

	@Override
	public void cleanup() {
		if(receiver != null) {
			receiver.interrupt();
		}
		if(agent != null) {
			agent.interrupt();
		}
		
		containers.clear();
		addedPlotters.clear();
	}

	@Override
	public void setup(PacketReceiver receiver, SessionStateAgent agent) {
		this.receiver = receiver;
		this.agent = agent;
	}

	
    private static final String RTP_LISTENER = "RTP Session Listener";
    private static final String RTSP_LISTENER = "RTSP Session Listener";
    private static final String SDP_LISTENER = "SDP Session Listener";
    private final String[] availableListeners = {RTP_LISTENER, SDP_LISTENER, RTSP_LISTENER};
    private List<DataPlotter<? extends SessionData>> addedPlotters = new LinkedList<DataPlotter<? extends SessionData>>();
    private HashMap<Class<? extends SessionData>, SessionDataContainer> containers = new HashMap<Class<? extends SessionData>, SessionDataContainer>();
    private GUIItemDisplayer displayer;
    private PacketReceiver receiver;
    private SessionStateAgent agent;
}
